package idv.jieh.web;

/*
  Update History
*/

import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;

/**
 * <p> 這個類別主要運作在 J2EE 上，包含以下幾種機制：</p>
 <table border="1" width="95%" align="center">
 <tr>
 <td>功能</td>
 <td>說明</td>
 </tr>
 <tr>
   <td><font color="#0000FF"><b>DatabaseAdapter</b></font></td>
   <td>
     這個interface定義了兩方法getConnection()和freeConnection()，他們分別代表的意義為取得Connection和釋放Connection的資源。
     要注意的是，這個類別並未定義這兩個方法的實作內容，而是使用者需要自行實作的。
   </td>
 </tr>
 <tr>
   <td><b><font color="#0000FF">Passdata</font></b></td>
   <td>
     <b><font color="#FF0000">資料載送庫</font></b>
     ，代替工程師的session需求，把個別程式需要的資料傳遞以專屬的機制處理。Passdata存放一些需要長期使用的資訊，並透過這個類別控制資源的運用。比如需要跨越數個作業流程的資料。在這個類別中，我們可以呼叫的方法有addPassdata(),destroyPassdata(),getPassdata(),passdataContainsKey(),removePassdata()控制資料載送庫。
   </td>
 </tr>
 <tr>
   <td><b><font color="#0000FF">TempResource</font></b></td>
   <td>
     <b><font color="#FF0000">資料暫存庫</font></b>
    ，代替工程師的session需求，把程式需要的短暫資料交流以專屬的機制處理，並要求使用完畢後馬上呼叫clearTempResource()清除。或許你會使用更久，但是切記一點放在這裡的資料是不保險的。這樣的機制是為了把不重要的但是卻需要傳送的資料，和重要的分開，使資源的利用更有效率。在這個類別中可以呼叫的方法有putTempResource(), getTempResource(), clearTempResource() 控制資料暫存庫。
   </td>
 </tr>
 <tr>
   <td><b><font color="#0000FF">Object Fa\u00E7ade</font></b></td>
   <td>
    在系統架構中初始化較複雜或功能重要的物件，由UserOnline內建構以提供所有程式便於操作，例如使用者資訊、使用者權限、選單物件…等。
   </td>
 </tr>
 </table>
 * @version 1.1
 * @author jieh
 */

abstract public class OnlineResource implements
  java.io.Serializable,
  HttpSessionBindingListener,
  idv.jieh.commons.sql.DatabaseAdapter,
  OnlineCheckDoor{

// page history control -- begin

//  public static enum PAGE_HISTORY_IDX{
//    // [施工中]定義第一頁。
//    FIRST_PAGE,
//    // [施工中]定義最後一頁。
//    LAST_PAGE,
//  }
//  private java.util.LinkedList pageHistory = new LinkedList();

//  public boolean sendRedirect(
//      javax.servlet.http.HttpServletResponse rp,
//      int page)
//      throws java.io.IOException {
//    if(pageHistory.size() > 0){
//      rp.sendRedirect(history(page));
//      return true;
//    }
//    return false;
//  }

  /**
   * [施工中]清除瀏覽過的網頁紀錄。<p>
   */
//  public void clearHistory(){
//    pageHistory.clear();
//  }

  /**
   * [施工中]瀏覽過的網頁紀錄。<p>
   * @param page 頁數。
   * @return 傳回頁面資料。
   */
//  public String history(PAGE_HISTORY_IDX page) {
//    switch (page) {
//      case LAST_PAGE:
//        return pageHistory.getLast().toString();
//      case FIRST_PAGE:
//        return pageHistory.getFirst().toString();
//      default:
//        return pageHistory.get(page).toString();
//    }
//  }

// page history control -- end

// *************************** 以上為施工區 ***************************

  private static final long serialVersionUID = -5847399975230348222L;

  protected idv.jieh.commons.util.DeBuger dbr = new idv.jieh.commons.util.DeBuger("OnlineResource");;

// facade Container Control -- begin (佛ˇ~~~殺ˋ!的)

  protected Hashtable facade_container = new Hashtable();
  abstract protected boolean defineFacade(Object key);
  public void removeFacade(Object key) { this.facade_container.remove(key); }

  public Object findFacade(Object key) {
    if (!facade_container.containsKey(key) &&
        !defineFacade(key)) {
      this.noKey(key);
    }
    return facade_container.get(key);
  }

// facade Container Control -- end

// Temp Resource Control -- begin
  private HashMap tmp_resource = new HashMap();
  public void clearTempResource() { tmp_resource.clear(); }
  public Object getTempResource(Object key) { return tmp_resource.get(key); }

  /**
   * 資源暫存庫。<p>
   * 這裡可以放置不重要，但是在短期內卻必須傳送給其他物件使用的資料。
   * 並且應該在使用結束後馬上呼叫 <u>clearTempResource()</u> 處理掉，以節省資源。
   * @param key 索引值。
   * @param value 欲保存的資料。
   */
  public void putTempResource(Object key, Object value) { tmp_resource.put(key, value); }

// Temp Resource Control -- end

  /**
   * 移除所有被這個物件保留的 Connection。<p>
   * 如果繼承這個類別的物件有保留 Connection，請在這個方法裡面撰寫清除的程式，
   * 當 Application server 將這個物件自 Session scope 移除時，
   * 內定會呼叫這個方法。
   */
  abstract protected void freeResources();

  // 資料載送庫。
  private Hashtable passdata = new Hashtable();

  /**
   * 指定取出在資料載送庫的一個物件。<p>
   * 使用者輸入一個合法的 key 值到資料載送庫，如果尋找到相對應的物件時便傳回。
   * @param key 搜尋資料的 key。
   * @return Object 在資料載送庫中找到的物件。
   */
  public Object getPassdata(Object key) {
    if (passdata.containsKey(key)) {
      return passdata.get(key);
    } else {
      throw this.noKey(key);
    }
  }

  /**
   * 合併一組資料載送庫到已存在的資料載送庫。<p>
   * 這個方法會將傳入的 <code>Hashtable</code> 直接加入資料載送庫內，之前的資料並不會清除。
   * @param ht 使用者想要加入的資料。
   */
  public void addPassdata(Hashtable ht) {
    Enumeration key = ht.keys();
    Enumeration value = ht.elements();
    while (key.hasMoreElements()) {
      passdata.put(key.nextElement(), value.nextElement());
    }
  }

  /**
   * 加入一個物件到資料載送庫<p>
   * 這個方法會依照使用者輸入的 key 值和 Object，加一筆資料到資料載送庫內。
   * @param key 使用者想要加到資料載送庫裡物件的索引值。
   * @param value 使用者要放到資料載送庫的資料或物件。
   */
  public void addPassdata(Object key, Object value) { passdata.put(key, value); }

  /**
   * 移除指定的資料載送庫內的一筆資料。<p>
   * 使用者輸入所要移除物件的 key。
   * @param key 使用者想要移除資料載送庫裡物件的索引值。
   */
  public void removePassdata(Object key) {
    if (passdata.containsKey(key)) {
      passdata.remove(key);
    }
  }

  /**
   * 詢問一組資料是否存在。<p>
   * 使用者輸入要比對的 key，如果這個 key 存在的話就傳回 true，否則傳回 false。
   * @param o 要比對的 key。
   * @return true：這個 key 存在；false：這個 key 不存在。
   */
  public boolean passdataContainsKey(Object o) {
    return passdata.containsKey(o);
  }

  /**
   * 清除所裝載的資料。
   */
  public void destroyPassdata() { passdata.clear(); }

  /**
   * 資料移出 Session 。<p>
   * 當這個物件被 Application Server 自 Session Sccope 消除時，將會呼叫此方法。<p>
   * 目前內定處理的事項如下：<p>
   * 1. 呼叫這個物件的 freeAllConnections method。
   * @param event HttpSessionBindingEvent Object。
   */
  public void valueUnbound(HttpSessionBindingEvent event) {
    this.freeResources();
  }

  public void valueBound(HttpSessionBindingEvent event) { }

  // 透過 OnlineResource 取的暫存資源不存在的警告訊息。
  private NullPointerException noKey(Object key) {
    StringBuilder msg = new StringBuilder();
    msg.append("\n\n <font color='red'><b>");
    msg.append(" Your key - [").append(key).append("]");
    msg.append(" were not in passdata! ");
    msg.append(" 您所輸入的 key - [").append(key).append("]");
    msg.append(" 並不存在！");
    msg.append(" </b></font>\n");
    dbr.exception(new NullPointerException(msg.toString()));
    return new NullPointerException(msg.toString());
  }

  // security control -- begin

  public static final String USERONLINE_SESSION_NAME = "USERONLINE_SESSION_NAME";
  private static enum CHECKDOOR_TYPES{NORMAL, COOKIE}

  /**
   * JSP 使用阻擋非法入侵的使用者。<P>
   * 如認證失敗則會讀取 web.xml 內 <CHECKDOOR_PATH> 的設定將網頁導向該路徑。
   * @param pc PageContext
   * @return boolean true：合法使用者；非法使用者。
   * @throws IOException
   */
  public boolean checkDoor(javax.servlet.jsp.PageContext pc) throws java.io.IOException {
    return new MyWebORUtility().checkDoor(pc.getServletContext(), (HttpServletRequest)pc.getRequest(), (HttpServletResponse)pc.getResponse());
  }

// security control -- end

} // class end
